package com.nakamachizu.service.mixi;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import net.oauth.OAuth;
import net.oauth.OAuthAccessor;
import net.oauth.OAuthConsumer;
import net.oauth.OAuthMessage;
import net.oauth.OAuthServiceProvider;
import net.oauth.OAuthValidator;
import net.oauth.SimpleOAuthValidator;
import net.oauth.signature.RSA_SHA1;

import org.slim3.datastore.Datastore;

import com.nakamachizu.meta.mixi.PublicKeyDataMeta;
import com.nakamachizu.model.mixi.PublicKeyData;


public class ValidatingSignedRequestsService {

    public static final String OPENSOSIAL_APP_ID = "opensocial_app_id";
    
    public static final String OPENSOSIAL_OWNER_ID = "opensocial_owner_id";
    
    public static final String OPENSOSIAL_VIEWER_ID = "opensocial_viewer_id";
    
    
    public Map<String, String> verifyFetch(HttpServletRequest request) throws Exception{

        Map<String, String>result = null;

        PublicKeyDataMeta meta = PublicKeyDataMeta.get();
        String publicKey = request.getParameter("xoauth_signature_publickey");
        PublicKeyData pkd = Datastore.query(meta).filter(meta.xoauthSignaturePublickey.equal(publicKey)).asSingle();
        if(pkd == null){
            throw new Exception("public key data not found");
        }
        OAuthServiceProvider provider = new OAuthServiceProvider(null, null, null);
        OAuthConsumer consumer = new OAuthConsumer(null, "mixi.jp", null, provider);
        consumer.setProperty(RSA_SHA1.X509_CERTIFICATE, pkd.getCertificate().getValue());

        String method = request.getMethod();
        String requestUrl = getRequestUrl(request);
        List<OAuth.Parameter> requestParameters = getRequestParameters(request);

        //OAuthMessage message = OAuthServlet.getMessage(request, null);
        //log.info("requestUrl:" + requestUrl);
        OAuthMessage message = new OAuthMessage(method, requestUrl, requestParameters);

        OAuthValidator validator = null;
        validator = new SimpleOAuthValidator();
        OAuthAccessor accessor = new OAuthAccessor(consumer);
        //VALIDATING SIGNATURE
        validator.validateMessage(message, accessor);

        result = new HashMap<String, String>();
        for (java.util.Map.Entry<String,String> param : message.getParameters()) {
            String key = param.getKey().toString();
            String value = (String)param.getValue();
            result.put(key, value);

        }

        return result;
    }
    
    /**
     * Constructs and returns the full URL associated with the passed request
     * object.
     *
     * @param  request Servlet request object with methods for retrieving the
     *         various components of the request URL
     */
    public static String getRequestUrl(HttpServletRequest request) {
          StringBuilder requestUrl = new StringBuilder();
          String scheme = request.getScheme();
          //int port = request.getServerPort();

          requestUrl.append(scheme);
          requestUrl.append("://");
          requestUrl.append(request.getServerName());

          /**
          if ((scheme.equals("http") && port != 80)
                  || (scheme.equals("https") && port != 443)) {
              requestUrl.append(":");
              requestUrl.append(port);
          }
          */

          requestUrl.append(request.getContextPath());
          requestUrl.append(request.getServletPath());

          return requestUrl.toString();
    }
    
    /**
     * Constructs and returns a List of OAuth.Parameter objects, one per
     * parameter in the passed request.
     *
     * @param  request Servlet request object with methods for retrieving the
     *         full set of parameters passed with the request
     */
    public List<OAuth.Parameter> getRequestParameters(HttpServletRequest request) {

        List<OAuth.Parameter> parameters = new ArrayList<OAuth.Parameter>();

        for (Object e : request.getParameterMap().entrySet()) {
            Map.Entry entry = (Map.Entry) e;

            String key = null;
            String[] values = null;
            if (entry.getKey() instanceof String) {
                key = (String) entry.getKey();
            }else{
                key = entry.getKey().toString();
            }
            if (entry.getValue() instanceof String[]) {
                values = (String[]) entry.getValue();
                for(String v : values){
                    //log.info("array:" + v);
                    parameters.add(new OAuth.Parameter(key,v));
                }
            }else if (entry.getValue() instanceof String) {
                String v = (String)entry.getValue();
                //log.info("str:" + v);
                parameters.add(new OAuth.Parameter(key, v));
            }


        }

        return parameters;
    }
}
